package com.sdehualu.utils;

import org.apache.spark.sql.Row;
import org.apache.spark.sql.RowFactory;
import ucar.ma2.Array;
import ucar.ma2.ArrayDouble;
import ucar.ma2.ArrayString;
import ucar.nc2.Dimension;
import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable;
import ucar.nc2.dataset.NetcdfDataset;
import ucar.nc2.units.DateUnit;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author: 吴敬超
 * @Date: 2021/7/19 16:39
 */
public class NetCDFInternalUtils {


    /**
     * @param timeVariable 时间相关的var
     * @return 时间var的units
     */
    public DateUnit readTimeUnit(Variable timeVariable) {
        try {
            String unitString = timeVariable.getUnitsString();

            //if present, replace . by : in the timeZone specification in the unitString,
            //e.g. change "days since 2011-09-19 06:0:0.0 0.00" to "days since 2011-09-19 06:0:0.0 0:00".
            //This is a workaround implemented for FEWS-6544.
            String[] parts = unitString.split("\\s+");
            if (parts.length > 0 && parts[parts.length - 1].matches(".?\\d{1,2}\\.\\d{2}")) {
                //if a timeZone specification is present, then it is always the last part, see
                //http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.5/cf-conventions.html#time-coordinate
                parts[parts.length - 1] = parts[parts.length - 1].replaceFirst("\\.", ":");
                StringBuilder buffer = new StringBuilder(parts[0]);
                for (int n = 1; n < parts.length; n++) {
                    buffer.append(' ').append(parts[n]);
                }
                unitString = buffer.toString();
            }

            return new DateUnit(unitString);
        } catch (Exception e) {
            //if the given variable does not have a unit of time.
            return null;
        }
    }


    /**
     * @param timeVariable 时间相关的var
     * @return 把时间变量转成时间戳放进数组中返回
     * @throws IOException
     */
    public long[] readTimes(Variable timeVariable) throws IOException {
        if (timeVariable == null) {
            throw new RuntimeException("Time variable not present");
        }

        //read times.
        Array timeArray = timeVariable.read();
        double[] times = (double[]) timeArray.get1DJavaArray(Double.class);

        //convert times.
        long[] convertedTimes = new long[times.length];
        DateUnit dateUnit = readTimeUnit(timeVariable);
        if (dateUnit == null) {
            throw new IOException("Invalid date time unit string has been coded in the file: '" + timeVariable.getUnitsString() +
                    "'.  Unit string should be for example: 'seconds since 2012-01-30 00:00:00'");

        }
        for (int i = 0; i < times.length; i++) {
            Date date = dateUnit.makeDate(times[i]);
            if (date != null) {
                convertedTimes[i] = date.getTime();
            } else {//if date is null.
                convertedTimes[i] = 0;
            }
        }
        return convertedTimes;
    }


    /**
     * @param timeVariable 时间相关的var
     * @param sdfpar       时间格式
     * @return 时间格式的集合
     * @throws IOException
     */
    public String[] readTimes(Variable timeVariable, String sdfpar) throws IOException {


        SimpleDateFormat sdf = new SimpleDateFormat(sdfpar);
        //时间不是北京时间，是格林尼治时间
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

        if (timeVariable == null) {
            throw new RuntimeException("Time variable not present");
        }

        //read times.
        Array timeArray = timeVariable.read();
        double[] times = (double[]) timeArray.get1DJavaArray(Double.class);

        //convert times.
        String[] convertedTimes = new String[times.length];

        DateUnit dateUnit = readTimeUnit(timeVariable);
        if (dateUnit == null) {

            throw new IOException("Invalid date time unit string has been coded in the file: '" + timeVariable.getUnitsString() +
                    "'.  Unit string should be for example: 'seconds since 2012-01-30 00:00:00'");

        }
        for (int i = 0; i < times.length; i++) {
            Date date = dateUnit.makeDate(times[i]);
            // date.getTimezoneOffset()

            if (date != null) {

                convertedTimes[i] = sdf.format(date);

            } else {//if date is null.
                convertedTimes[i] = sdf.format(new Date(0));
            }
        }
        return convertedTimes;
    }


    /**
     * @param Variable
     * @param sdfpar
     * @return
     * @throws IOException
     */
    public String[] var1D(Variable Variable, String sdfpar) throws IOException {


        String varname = Variable.getName();

        if ((varname.equals("time")) && (Variable.getUnitsString() != null)) {

            return readTimes(Variable, sdfpar);

        } else {


            float[] zj = (float[]) Variable.read().copyTo1DJavaArray();


            String[] su1d = new String[zj.length];

            for (int i = 0; i < zj.length; i++) {

                su1d[i] = String.valueOf(zj[i]);
            }
            return su1d;
            // double[] times = (double[]) timeArray.get1DJavaArray(Double.class);

            // return (String[]) Variable.read().get1DJavaArray(String.class);
        }


        // return (String[]) Variable.read().copyTo1DJavaArray();


        // return null;

    }


    public String[] vartime1D(Variable Variable, String sdfpar) throws IOException {


        String varname = Variable.getName();

        if ((varname.equals("time")) && (Variable.getUnitsString() != null)) {

            return readTimes(Variable, sdfpar);

        }


        // return (String[]) Variable.read().copyTo1DJavaArray();


        return null;

    }


    /**
     * @param Variablename
     * @param sdfpar
     * @return
     * @throws IOException
     */
    public String[] var1Dlist(String Variablename, String sdfpar) throws IOException {


        // String varname = Variablename;
        // if ()
        //
        // if ((varname.equals("time")) && (Variable.getUnitsString() != null)) {
        //
        //     return readTimes(Variable, sdfpar);
        //
        // }
        //
        //
        // return (String[]) Variable.read().copyTo1DJavaArray();


        return null;

    }


    /**
     * 判断是否存在此变量
     *
     * @param netcdfDataset 数据集
     * @param varname       变量名
     * @return
     */
    public boolean Varflag(NetcdfDataset netcdfDataset, String varname) {

        List<Variable> variableList = netcdfDataset.getVariables();

        for (Variable var : variableList) {

            String getname = var.getName();
            System.out.println(getname);


            if (getname.equals(varname)) {

                return true;
            }
        }

        return false;
    }


    /**
     * @param variableList
     * @param varname
     * @return
     */
    public boolean Varflag(List<Variable> variableList, String varname) {


        for (Variable var : variableList) {

            String getname = var.getName();
            System.out.println(getname);


            if (getname.equals(varname)) {

                return true;
            }
        }

        return false;
    }


    public boolean zeroDimensions(NetcdfDataset netcdfDataset, String varname) {


        // dataFile.findVariable("U");

        Variable variable = netcdfDataset.findVariable(varname);
        int varDimensionsSize = variable.getDimensions().size();

        return varDimensionsSize == 0;
    }

    /**
     * 返回var中变量个数
     *
     * @param netcdfDataset 数据集
     * @param varname       var
     * @return
     */
    public int sizeDimensions(NetcdfDataset netcdfDataset, String varname) {


        // dataFile.findVariable("U");

        Variable variable = netcdfDataset.findVariable(varname);
        // int varDimensionsSize = variable.getDimensions().size();

        return variable.getDimensions().size();
    }


    /**
     * [time = 24;, lat = 1101;, lon = 1051;]
     *
     * @param netcdfDataset
     * @param varname
     * @return
     */
    public List<Dimension> vards(NetcdfDataset netcdfDataset, String varname) {
        Variable variable = netcdfDataset.findVariable(varname);
        return variable.getDimensions();

    }


    /**
     * 将一维的Variable 转成list。time需要进行时间格式转换
     *
     * @param variable
     * @return
     */
    public List<String> vartolist(Variable variable) {


        return null;
    }


    /**
     * @param parnum   分区的编号
     * @param vards    var 变量 DimensionsSize
     * @param variable 变量
     * @param dilist   var Dimensions  var的list
     * @param firflag  第一个Dimension 是否大于1 是,为ture
     * @return
     */
    public List<Row> swithlist(int parnum, int vards, Variable variable, List<String[]> dilist, boolean firflag) {

        List<Row> rowList = null;

        try {

            switch (vards) {

                //一维的 var
                case 1:
                    float floatvar1[] = (float[]) variable.read().copyToNDJavaArray();

                    rowList.add(RowFactory.create(floatvar1[parnum]));

                    return rowList;

                case 2:
                    float floatvar2[][] = (float[][]) variable.read().copyToNDJavaArray();
                    //
                    // dilist.get(0);
                    // dilist.get(1);

                    //2维的var 且根据1 dimension 分区
                    if (firflag) {

                        for (int i = 0; i < floatvar2[parnum].length; i++) {

                            rowList.add(RowFactory.create(
                                    dilist.get(0)[parnum],
                                    dilist.get(1)[i],
                                    floatvar2[parnum][i]));
                        }

                        //2维的var 且根据2 dimension 分区
                    } else {

                        rowList.add(RowFactory.create(
                                dilist.get(0)[0],
                                dilist.get(1)[parnum],
                                floatvar2[0][parnum]));
                    }

                    return rowList;

                case 3:
                    float floatvar3[][][] = (float[][][]) variable.read().copyToNDJavaArray();

                    //3维数据，且根据1 dimension 分区
                    if (firflag) {
                        for (int i = 0; i < floatvar3[parnum].length; i++) {
                            for (int i2 = 0; i2 < floatvar3[parnum][i].length; i2++) {

                                rowList.add(RowFactory.create(
                                        dilist.get(0)[parnum],
                                        dilist.get(1)[i],
                                        dilist.get(2)[i2],
                                        floatvar3[parnum][i][i2]));
                            }
                        }
                        // 3维的var 且根据2 dimension 分区
                    } else {

                        for (int i = 0; i < floatvar3[0][parnum].length; i++) {

                            rowList.add(RowFactory.create(
                                    dilist.get(0)[0],
                                    dilist.get(1)[parnum],
                                    dilist.get(2)[i],
                                    floatvar3[0][parnum][i]));
                        }
                    }

                    return rowList;
                case 4:
                    float floatvar4[][][][] = (float[][][][]) variable.read().copyToNDJavaArray();

                    //4维数据，且根据1 dimension 分区
                    if (firflag) {
                        for (int i = 0; i < floatvar4[parnum].length; i++) {

                            for (int i2 = 0; i2 < floatvar4[parnum][i].length; i2++) {

                                for (int i3 = 0; i3 < floatvar4[parnum][i][i2].length; i3++) {

                                    rowList.add(RowFactory.create(
                                            dilist.get(0)[parnum],
                                            dilist.get(1)[i],
                                            dilist.get(2)[i2],
                                            dilist.get(3)[i3],
                                            floatvar4[parnum][i][i2][i3]));
                                }
                            }
                        }

                        //     4维的var 且根据2 dimension 分区
                    } else {

                        for (int i = 0; i < floatvar4[0][parnum].length; i++) {
                            for (int i2 = 0; i2 < floatvar4[0][parnum][i].length; i2++) {

                                rowList.add(RowFactory.create(
                                        dilist.get(0)[0],
                                        dilist.get(1)[parnum],
                                        dilist.get(2)[i],
                                        dilist.get(3)[i2],
                                        floatvar4[0][parnum][i][i2]));
                            }
                        }

                    }


                    return rowList;
                case 5:
                    float floatvar5[][][][][] = (float[][][][][]) variable.read().copyToNDJavaArray();

                    //且根据1 dimension 分区
                    if (firflag) {

                        for (int i = 0; i < floatvar5[parnum].length; i++) {

                            for (int i2 = 0; i2 < floatvar5[parnum][i].length; i2++) {

                                for (int i3 = 0; i3 < floatvar5[parnum][i][i2].length; i3++) {
                                    for (int i4 = 0; i4 < floatvar5[parnum][i][i2][i3].length; i4++) {

                                        rowList.add(RowFactory.create(
                                                dilist.get(0)[parnum],
                                                dilist.get(1)[i],
                                                dilist.get(2)[i2],
                                                dilist.get(3)[i3],
                                                dilist.get(4)[i4],
                                                floatvar5[parnum][i][i2][i3][i4]));
                                    }
                                }
                            }
                        }

                        //    根据2 dimension 分区
                    } else {


                        for (int i = 0; i < floatvar5[0][parnum].length; i++) {

                            for (int i2 = 0; i2 < floatvar5[0][parnum][i].length; i2++) {

                                for (int i3 = 0; i3 < floatvar5[0][parnum][i][i2].length; i3++) {
                                    rowList.add(RowFactory.create(
                                            dilist.get(0)[0],
                                            dilist.get(1)[parnum],
                                            dilist.get(2)[i],
                                            dilist.get(3)[i2],
                                            dilist.get(4)[i3],
                                            floatvar5[0][parnum][i][i2][i3]));
                                }
                            }
                        }


                    }


                    return rowList;
                case 6:
                    float floatvar6[][][][][][] = (float[][][][][][]) variable.read().copyToNDJavaArray();

                    //且根据1 dimension 分区
                    if (firflag) {

                        for (int i = 0; i < floatvar6[parnum].length; i++) {

                            for (int i2 = 0; i2 < floatvar6[parnum][i].length; i2++) {

                                for (int i3 = 0; i3 < floatvar6[parnum][i][i2].length; i3++) {
                                    for (int i4 = 0; i4 < floatvar6[parnum][i][i2][i3].length; i4++) {

                                        for (int i5 = 0; i5 < floatvar6[parnum][i][i2][i3].length; i5++) {


                                            rowList.add(RowFactory.create(
                                                    dilist.get(0)[parnum],
                                                    dilist.get(1)[i],
                                                    dilist.get(2)[i2],
                                                    dilist.get(3)[i3],
                                                    dilist.get(4)[i4],
                                                    dilist.get(5)[i5],

                                                    floatvar6[parnum][i][i2][i3][i4][i5]));


                                        }


                                    }
                                }
                            }
                        }
                        //根据2 dimension 分区
                    } else {


                        for (int i = 0; i < floatvar6[0][parnum].length; i++) {

                            for (int i2 = 0; i2 < floatvar6[0][parnum][i].length; i2++) {

                                for (int i3 = 0; i3 < floatvar6[0][parnum][i][i2].length; i3++) {
                                    for (int i4 = 0; i4 < floatvar6[0][parnum][i][i2][i3].length; i4++) {


                                        rowList.add(RowFactory.create(
                                                dilist.get(0)[0],
                                                dilist.get(1)[parnum],
                                                dilist.get(2)[i],
                                                dilist.get(3)[i2],
                                                dilist.get(4)[i3],
                                                dilist.get(5)[i4],

                                                floatvar6[0][parnum][i][i2][i3][i4]));

                                    }

                                }
                            }
                        }
                    }


                    return rowList;


                // case 7:
                //     float floatvar7[][][][][][][] = (float[][][][][][][]) variable.read().copyToNDJavaArray();
                //     // return new ArrayDouble.D6(index, storage);
                //     return rowList;

                default:
                    return null;
            }


        } catch (IOException e) {
            e.printStackTrace();
        }


        return null;

    }


    // public static void main(String[] args) throws Exception {
    //
    //
    //     String filename = "D:/nc2json/data.nc";
    //
    //     NetcdfFile dataFile = dataFile = NetcdfFile.open(filename);
    //
    //
    //     NetCDFInternalUtils netCDFInternalUtils = new NetCDFInternalUtils();
    //
    //     String[] ad1 = netCDFInternalUtils.var1D(dataFile.findVariable("time"), "yyyy-MM-dd_HH:mm:ss");
    //
    //     System.out.println(ad1[0]);
    //     System.out.println(ad1[1]);
    //     System.out.println(ad1[2]);
    //
    //
    // }


}
